package edu.ccut.saturn.component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SaturnAuthorityManager {

	private static final String URL_SEPARATOR = "/";

	private static final String KEY_SEPARATOR = "::";

	private static final String LOGGER_KEY_BUNDLE_SERVICE = SaturnLoggerManager.LOGGER_KEY_BUNDLE_SERVICE;

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(LOGGER_KEY_BUNDLE_SERVICE);

	private Map<String, IBundleAuthorityInfo> bundleAuthorityInfos;

	private List<IAuthorityResourceInfo> allResourcesCache;

	private List<IAuthorityRoleInfo> allRolesCache;

	private static SaturnAuthorityManager instance;

	static {
		instance = new SaturnAuthorityManager();
	}

	private SaturnAuthorityManager() {
		this.bundleAuthorityInfos = new HashMap<String, IBundleAuthorityInfo>();
		this.allResourcesCache = new ArrayList<IAuthorityResourceInfo>();
		this.allRolesCache = new ArrayList<IAuthorityRoleInfo>();
	}

	public static SaturnAuthorityManager getInstance() {
		return instance;
	}

	public void addBundleAuthorityInfo(IBundleInfo bundleInfo) {
		IBundleAuthorityInfo bundleAuthorityInfo = bundleInfo
				.getBundleAuthorityInfo();

		this.bundleAuthorityInfos.put(bundleInfo.getBundleSymbolicName(),
				bundleAuthorityInfo);

		this.allResourcesCache.addAll(bundleAuthorityInfo.getResourceInfos());
		this.allRolesCache.addAll(bundleAuthorityInfo.getRoleInfos());
		logger.debug("add bundleAuthorityInfo key \""
				+ bundleInfo.getBundleSymbolicName() + "\"");
	}

	public void removeBundleAuthorityInfo(String bundleSymbolicName) {

		if (this.bundleAuthorityInfos.containsKey(bundleSymbolicName)) {
			IBundleAuthorityInfo bundleAuthorityInfo = this.bundleAuthorityInfos
					.get(bundleSymbolicName);

			this.allResourcesCache.removeAll(bundleAuthorityInfo
					.getResourceInfos());

			this.allRolesCache.removeAll(bundleAuthorityInfo.getRoleInfos());
			this.bundleAuthorityInfos.remove(bundleSymbolicName);
			logger.debug("remove bundleWorkFlowInfo key is : \""
					+ bundleSymbolicName + "\"");

			return;
		}
		logger
				.warn("failed to remove bundleAuthorityInfo, because the bundle key : \""
						+ bundleSymbolicName + "\" is not valid");
	}

	public IBundleAuthorityInfo getAuthorityInfo(String bundleSymbolicName)
			throws SaturnComponentException {

		IBundleAuthorityInfo bundleAuthorityInfo = this.bundleAuthorityInfos
				.get(bundleSymbolicName);

		if (bundleAuthorityInfo == null) {
			throw new SaturnComponentException(
					"Failed to get authority config file ;can't find bundle with symbolicName = ["
							+ bundleSymbolicName + "] ");
		}
		return bundleAuthorityInfo;
	}

	public List<IAuthorityResourceInfo> getAllResources() {
		return this.allResourcesCache;
	}

	public List<IAuthorityRoleInfo> getAllRoles() {
		return this.allRolesCache;
	}

	public List<Map<String, String>> getBundleNameList() {
		List<Map<String, String>> nameList = new ArrayList<Map<String, String>>();
		Map<String, String> allItem = new HashMap<String, String>();
		allItem.put("key", "");
		allItem.put("value", "all bundles");
		nameList.add(allItem);
		Set<String> keySet = this.bundleAuthorityInfos.keySet();

		if (keySet != null) {

			for (String key : keySet) {
				Map<String, String> item = new HashMap<String, String>();
				item.put("key", key);
				item.put("value", key);
				nameList.add(item);
			}
		}
		return nameList;
	}

	public List<IAuthorityResourceInfo> getSpecieledBundleResources(
			String bundleSymbolicName) throws SaturnComponentException {

		IBundleAuthorityInfo bundleAuthorityInfo = this
				.getAuthorityInfo(bundleSymbolicName);

		List<IAuthorityResourceInfo> resourceList = bundleAuthorityInfo
				.getResourceInfos();

		if (resourceList.size() <= 0) {
			return null;
		}
		return resourceList;
	}

	public List<IAuthorityResourceInfo> getResourcesOfSpecialedRole(
			String roleKey) {

		List<IAuthorityResourceInfo> resourceList = null;
		List<IAuthorityRoleInfo> roleList = this.getAllRoles();

		if (roleList != null) {

			for (IAuthorityRoleInfo role : roleList) {

				if (roleKey.equals(role.getRoleKey())) {
					resourceList = role.getResourceInfos();
					break;
				}
			}
		}
		return resourceList;
	}

	public boolean isNeedAuthorityResource(String resources) {

		if (resources != null && !"".equals(resources)) {
			int index = resources.indexOf(URL_SEPARATOR, 1);

			if (index > 0) {
				String title = resources.substring(1, index);
				String tier = resources.substring(index);

				if (title.endsWith(KEY_SEPARATOR)) {
					title = title.substring(0, title.length() - 2);
				}
				return resourceMapping(title, tier);
			}
		}
		return false;
	}

	private boolean resourceMapping(String title, String tier) {

		if (this.bundleAuthorityInfos.keySet().contains(title)) {

			try {
				List<IAuthorityResourceInfo> resourceInfos = this
						.getSpecieledBundleResources(title);

				if (resourceInfos != null) {

					for (IAuthorityResourceInfo resourceInfo : resourceInfos) {
						String resourceValue = resourceInfo.getValue();
						int index = resourceValue.indexOf(URL_SEPARATOR, 1);
						resourceValue = resourceValue.substring(index);

						if ("/*".equals(resourceValue)) {
							return true;

						} else if (resourceValue != null) {

							if (resourceValue.contains("*")) {
								int separator = resourceValue
										.lastIndexOf(URL_SEPARATOR);

								String resourcePath = resourceValue.substring(
										0, separator + 1);

								String resourceName = resourceValue
										.substring(separator + 1);

								return doMapping(resourcePath, resourceName,
										tier);

							} else if (tier.equals(resourceValue)) {
								return true;
							}
						}
					}
				}

			} catch (SaturnComponentException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	/**
	 * 对资源的权限有通配符的情况进行匹配的方法
	 * 
	 * @param resourcePath
	 * @param resourceName
	 * @param tier
	 * @return
	 */
	private boolean doMapping(String resourcePath, String resourceName,
			String tier) {

		if (resourcePath.endsWith("/**/")) {

			if (!tier.startsWith(resourcePath)) {

				String path = resourcePath.substring(0,
						resourcePath.length() - 3);

				if (tier.startsWith(path)) {
					return doResourceNameMapping(resourceName, tier);
				}
				return false;
			}

		} else if (tier.startsWith(resourcePath)) {
			return doResourceNameMapping(resourceName, tier);
		}
		return false;
	}

	/**
	 * 对资源名的匹配
	 * 
	 * @return
	 */
	private boolean doResourceNameMapping(String resourceName, String tier) {
		int index = tier.lastIndexOf(URL_SEPARATOR);
		String name = tier.substring(index + 1);
		int pointIndex = name.indexOf(".");

		if (pointIndex <= 0 || pointIndex >= (name.length() - 1)) {
			return false;
		}

		if (resourceName.contains("*")) {
			int nameSeparator = resourceName.indexOf(".");
			String prefix = resourceName.substring(0, nameSeparator);
			String suffix = resourceName.substring(nameSeparator + 1);

			if (prefix != null && suffix != null) {

				if (prefix.equals("*")) {

					if (suffix.equals("*")) {
						return true;

					} else if (name.substring(name.indexOf(".") + 1).equals(
							suffix)) {

						return true;
					}

				} else if (suffix.equals("*")) {

					if (name.substring(0, name.indexOf(".")).equals(prefix)) {
						return true;
					}

				} else if (name.equals(resourceName)) {
					return true;
				}
			}

		} else if (resourceName.equals(name)) {
			return true;
		}
		return false;
	}
}
